<template>
  <a-row gutter="16" class="course-management">
    <!-- 左侧分类树 -->
    <a-col :span="6">
      <a-card title="课程分类" bordered>
        <a-button type="primary" size="small" @click="openCategoryModal(null, 'add')" style="margin-bottom: 8px;">新增顶级分类</a-button>
        <a-tree
          :tree-data="categoryTree"
          :field-names="{ title: 'name', key: 'id', children: 'children' }"
          @select="onCategorySelect"
          :selectedKeys="selectedCategoryId ? [selectedCategoryId] : []"
          defaultExpandAll
        >
          <template #title="{ name, id, level, children }">
            <span class="category-tree-title">
              <span>{{ name }}</span>
              <span class="actions">
                <a-button
                  v-if="level !== 3"
                  type="link"
                  size="small"
                  @click.stop="openCategoryModal(id, 'add')"
                >新增</a-button>
                <a-button type="link" size="small" @click.stop="openCategoryModal(id, 'edit')">编辑</a-button>
                <a-popconfirm
                  v-if="!children || children.length === 0"
                  title="确定删除该分类？"
                  @confirm="deleteCategory(id)"
                >
                  <a-button type="link" size="small" danger>删除</a-button>
                </a-popconfirm>
              </span>
            </span>
          </template>
        </a-tree>
      </a-card>
    </a-col>
    <!-- 右侧课程列表 -->
    <a-col :span="18">
      <div class="page-header">
        <h1>课程管理</h1>
        <a-button type="primary" @click="openCourseModal(null, 'add')">
          <template #icon>
            <PlusOutlined />
          </template>
          新增课程
        </a-button>
      </div>
      <div class="search-section">
        <a-input-search v-model:value="searchKeyword" placeholder="搜索课程名称" @search="handleSearch" />
        <a-button @click="resetFilters" style="margin-left: 16px;">重置筛选</a-button>
      </div>
      <div class="course-table">
        <a-table
          :columns="columns"
          :data-source="courses"
          :pagination="pagination"
          :loading="loading"
          row-key="id"
        >
          <template #bodyCell="{ column, record }">
            <template v-if="column.dataIndex === 'coverUrl'">
              <img :src="PIC_BASE_URL + record.coverUrl" :alt="record.title" class="course-cover" />
            </template>
            <template v-else-if="column.dataIndex === 'action'">
              <a-space>
                <a-button type="link" @click="openCourseModal(record, 'edit')">编辑</a-button>
                <a-button type="link" @click="manageOutline(record)">大纲</a-button>
                <a-popconfirm title="确定要删除这个课程吗？" @confirm="deleteCourse(record.id)">
                  <a-button type="link" danger>删除</a-button>
                </a-popconfirm>
              </a-space>
            </template>
          </template>
        </a-table>
      </div>
    </a-col>
  </a-row>

  <!-- 分类新增/编辑弹窗 -->
  <a-modal v-model:open="showCategoryModal" :title="categoryModalType === 'add' ? '新增分类' : '编辑分类'" @ok="handleCategoryModalOk" @cancel="showCategoryModal = false">
    <a-input v-model:value="categoryModalName" placeholder="请输入分类名称" />
  </a-modal>

  <!-- 课程新增/编辑弹窗 -->
  <a-modal v-model:open="showCourseModal" :title="courseModalType === 'add' ? '新增课程' : '编辑课程'" width="600px" @ok="handleCourseModalOk" @cancel="showCourseModal = false">
    <a-form ref="formRef" :model="courseForm" :rules="formRules" layout="vertical">
      <a-form-item label="课程名称" name="title">
        <a-input v-model:value="courseForm.title" placeholder="请输入课程名称" />
      </a-form-item>
      <a-form-item label="课程分类" name="categoryId">
        <a-tree-select
          v-model:value="courseForm.categoryId"
          :tree-data="categoryTreeForSelect"
          :field-names="{ label: 'name', value: 'id', children: 'children' }"
          placeholder="请选择分类"
          allow-clear
        />
      </a-form-item>
      <a-form-item label="课程封面" name="coverUrl">
        <a-upload v-model:file-list="fileList" list-type="picture-card" :show-upload-list="false" :before-upload="beforeUpload">
          <div v-if="courseForm.coverUrl" style="position: relative; width: 120px; height: 90px;">
            <img :src="PIC_BASE_URL + courseForm.coverUrl" alt="cover" style="width: 100%; height: 100%; object-fit: cover; border-radius: 10px;" />
            <CloseCircleOutlined
              @click.stop="removeCover"
              class="cover-remove-btn"
            />
          </div>
          <div v-else>
            <PlusOutlined />
            <div style="margin-top: 8px">上传封面</div>
          </div>
        </a-upload>
      </a-form-item>
      <a-form-item label="课程描述" name="description">
        <a-textarea v-model:value="courseForm.description" :rows="4" placeholder="请输入课程描述" />
      </a-form-item>
    </a-form>
  </a-modal>

  <!-- 课程大纲弹窗 -->
  <a-modal v-model:open="showOutlineModal" title="课程大纲" width="700px" @cancel="showOutlineModal = false" :footer="null">
    <a-button type="primary" size="small" @click="openOutlineModal(null, 'add')" style="margin-bottom: 8px;">新增章节</a-button>
    <a-tree
      :tree-data="outlineTree"
      :field-names="{ title: 'title', key: 'id', children: 'children' }"
      defaultExpandAll
    >
      <template #title="{ title, id, videoId, children, level }">
        <span class="outline-title">
          <span>{{ title }}</span>
          <span class="actions">
            <!-- 只有一级菜单可以新增子节点，二级菜单不能新增 -->
            <a-button
              v-if="level === 1"
              type="link"
              size="small"
              @click.stop="openOutlineModal(id, 'add')"
            >新增</a-button>
            <!-- 编辑按钮所有节点都可用 -->
            <a-button type="link" size="small" @click.stop="openOutlineModal(id, 'edit')">编辑</a-button>
            <!-- 一级菜单有子节点不能删除，二级菜单无子节点可删除 -->
            <a-popconfirm
              v-if="(level === 1 && (!children || children.length === 0)) || (level === 2 && (!children || children.length === 0))"
              title="确定删除该节点？"
              @confirm="deleteOutline(id)"
            >
              <a-button type="link" size="small" danger>删除</a-button>
            </a-popconfirm>
            <!-- 只有二级菜单（level=2）可以绑定视频 -->
            <a-button
              v-if="level === 2 && !videoId"
              type="default"
              size="small"
              @click.stop="bindVideo(id)"
              class="bind-video-btn"
            >绑定视频</a-button>
            <a-button
              v-if="level === 2 && videoId"
              type="default"
              size="small"
              @click.stop="bindVideo(id)"
              class="bind-video-btn-success"
            >
              <CheckCircleFilled style="color: #52c41a; margin-right: 3px; font-size: 15px;" />
              已绑定视频
            </a-button>
            <a-button
              v-if="level === 2 && videoId"
              type="link"
              size="small"
              @click.stop="previewVideo(videoId)"
              style="margin-left: 4px;"
            >预览</a-button>
          </span>
        </span>
      </template>
    </a-tree>
  </a-modal>

  <!-- 大纲新增/编辑弹窗 -->
  <a-modal v-model:open="showEditOutlineModal" :title="outlineModalType === 'add' ? '新增大纲节点' : '编辑大纲节点'" @ok="handleOutlineModalOk" @cancel="showEditOutlineModal = false">
    <a-input v-model:value="outlineModalName" placeholder="请输入章节/小节名称" />
  </a-modal>

  <!-- 绑定视频弹窗 -->
  <a-modal v-model:open="showBindVideoModal" title="绑定视频" @cancel="showBindVideoModal = false" :footer="null">
    <a-input-search
      v-model:value="videoSearchKeyword"
      placeholder="输入视频名称搜索"
      @search="fetchVideoList"
      style="margin-bottom: 12px;"
    />
    <a-table
      :columns="videoColumns"
      :data-source="videoList"
      :pagination="videoPagination"
      :loading="videoLoading"
      row-key="id"
      @change="handleVideoTableChange"
    >
      <template #bodyCell="{ column, record }">
        <template v-if="column.dataIndex === 'action'">
          <a-button type="link" @click="selectVideo(record)">选择</a-button>
        </template>
      </template>
    </a-table>
  </a-modal>

  <!-- 视频预览弹窗 -->
  <a-modal v-model:open="showPreviewModal" title="视频预览" width="700px" @cancel="showPreviewModal = false" :footer="null">
    <video v-if="previewVideoUrl" :src="previewVideoUrl" controls style="width: 100%; max-height: 400px;" />
    <div v-else>未找到视频资源</div>
  </a-modal>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { PlusOutlined, CloseCircleOutlined } from '@ant-design/icons-vue'
import SparkMD5 from 'spark-md5'
import type { FormInstance } from 'ant-design-vue'
import { getCourseCategoryTree, addCourseCategory, updateCourseCategory, deleteCourseCategory } from '@/api/bizCourseCategoryController'
import { getCoursePageList, addCourseBase, updateCourseBase, deleteCourseBase } from '@/api/bizCoursesBaseController'
import { uploadPic, deleteFile, getMediaFileList, getMediaFileById } from '@/api/BizMediaFileController'
import { getCourseOutlines, saveCourseOutlines, updateCourseOutlines, deleteCourseOutlines } from '@/api/bizCourseOutlinesController'
import { message } from 'ant-design-vue'
import { CheckCircleFilled } from '@ant-design/icons-vue'
// 假设有如下接口


const PIC_BASE_URL = import.meta.env.VITE_PIC_BASE_URL
const VIDEO_BASE_URL = import.meta.env.VITE_VIDEO_BASE_URL
// 分类树数据
const categoryTree = ref<any[]>([])
const selectedCategoryId = ref<number | null>(null)

// 页面加载时请求分类树
onMounted(async () => {
  await refreshCategoryTree()
})

async function refreshCategoryTree() {
  const res = await getCourseCategoryTree()
  const { code, data } = res.data || {}
  if (code === 0 && Array.isArray(data)) {
    const fixChildren = (list: any[]) => {
      list.forEach(item => {
        if (!item.children) item.children = []
        else fixChildren(item.children)
      })
    }
    fixChildren(data)
    categoryTree.value = data
  }
}

// 分类弹窗
const showCategoryModal = ref(false)
const categoryModalType = ref<'add' | 'edit'>('add')
const categoryModalName = ref('')
const categoryEditId = ref<number | null>(null)
const categoryParentId = ref<number | null>(null)
const categoryEditLevel = ref<number>(1)

function openCategoryModal(id: number | null, type: 'add' | 'edit') {
  categoryModalType.value = type
  if (type === 'add') {
    categoryModalName.value = ''
    categoryParentId.value = id
    categoryEditId.value = null
    // 计算 level
    if (!id) {
      categoryEditLevel.value = 1
    } else {
      // 查找父节点 level
      const parentNode = findCategoryNode(categoryTree.value, id)
      categoryEditLevel.value = parentNode ? (parentNode.level || 1) + 1 : 2
    }
  } else {
    // 查找当前节点
    if (id == null) return
    const node = findCategoryNode(categoryTree.value, id)
    categoryModalName.value = node?.name || ''
    categoryEditId.value = id
    categoryParentId.value = null
    categoryEditLevel.value = node?.level || 1
  }
  showCategoryModal.value = true
}

async function handleCategoryModalOk() {
  if (!categoryModalName.value) return
  if (categoryModalType.value === 'add') {
    // 新增分类
    const body = {
      name: categoryModalName.value,
      parentId: categoryParentId.value === null ? undefined : categoryParentId.value,
      level: categoryEditLevel.value,
    }
    await addCourseCategory(body)
  } else if (categoryModalType.value === 'edit' && categoryEditId.value) {
    // 编辑分类
    const node = findCategoryNode(categoryTree.value, categoryEditId.value)
    if (!node) return
    const body = {
      id: categoryEditId.value,
      name: categoryModalName.value,
      parentId: node.parentId === null ? undefined : node.parentId,
      level: node.level,
    }
    await updateCourseCategory(body)
  }
  showCategoryModal.value = false
  await refreshCategoryTree()
}

async function deleteCategory(id: number) {
  await deleteCourseCategory({ id })
  await refreshCategoryTree()
}

function findCategoryNode(nodes: any[], id: number): any {
  for (const node of nodes) {
    if (node.id === id) return node
    if (node.children) {
      const found = findCategoryNode(node.children, id)
      if (found) return found
    }
  }
  return null
}
function insertCategoryNode(nodes: any[], parentId: number, newNode: any): boolean {
  for (const node of nodes) {
    if (node.id === parentId) {
      if (!node.children) node.children = []
      node.children.push({ ...newNode, level: (node.level || 1) + 1, parent_id: node.id })
      return true
    }
    if (node.children && insertCategoryNode(node.children, parentId, newNode)) return true
  }
  return false
}
function removeCategoryNode(nodes: any[], id: number): boolean {
  for (let i = 0; i < nodes.length; i++) {
    if (nodes[i].id === id) {
      nodes.splice(i, 1)
      return true
    }
    if (nodes[i].children && removeCategoryNode(nodes[i].children, id)) return true
  }
  return false
}
function onCategorySelect(keys: number[], event: any) {
  const node = event.node;
  // 只要是最后一级（叶子节点）就查询课程
  if (node && (!node.children || node.children.length === 0)) {
    selectedCategoryId.value = node.id;
    pagination.current = 1;
    fetchCourses();
  } else {
    selectedCategoryId.value = null;
    courses.value = [];
    pagination.total = 0;
  }
}

// 递归为非叶子节点加 disabled: true
function markNonLeafDisabled(tree: any[]): any[] {
  return tree.map(node => {
    const hasChildren = node.children && node.children.length > 0
    return {
      ...node,
      disabled: hasChildren,
      children: hasChildren ? markNonLeafDisabled(node.children) : []
    }
  })
}
// 只允许选择叶子节点的分类树
const categoryTreeForSelect = computed(() => markNonLeafDisabled(categoryTree.value))

// 课程数据
const courses = ref<any[]>([])
const loading = ref(false)
const searchKeyword = ref('')
const showCourseModal = ref(false)
const courseModalType = ref<'add' | 'edit'>('add')
const courseEditId = ref<number | null>(null)
const fileList = ref<any[]>([])
const formRef = ref<FormInstance>()
const courseForm = reactive({
  id: null as number | null,
  title: '',
  categoryId: null as number | null,
  coverUrl: '',
  description: ''
})
const formRules = {
  title: [{ required: true, message: '请输入课程名称' }],
  categoryId: [{ required: true, message: '请选择课程分类' }],
  description: [{ required: true, message: '请输入课程描述' }]
}

// 递归获取所有子分类id
function getAllCategoryIds(tree: any[], id: number): number[] {
  const result: number[] = []
  function dfs(nodes: any[]) {
    for (const node of nodes) {
      if (node.id === id) {
        collect(node)
        break
      }
      if (node.children) dfs(node.children)
    }
  }
  function collect(node: any) {
    result.push(node.id)
    if (node.children) node.children.forEach(collect)
  }
  dfs(tree)
  return result
}

// 获取课程列表
const pagination = reactive({
  current: 1,
  pageSize: 10,
  total: 0,
  showSizeChanger: true,
  showQuickJumper: true,
  showTotal: (total: number) => `共 ${total} 条记录`,
  pageSizeOptions: ['10', '20', '50', '100']
})

async function fetchCourses() {
  loading.value = true
  let categoryId: number | undefined = undefined
  if (selectedCategoryId.value) {
    // 只传当前选中分类id，后端如需递归请自行处理
    categoryId = selectedCategoryId.value
  }
  const params = {
    coursePageListDto: {
      current: pagination.current,
      pageSize: pagination.pageSize,
      title: searchKeyword.value,
      categoryId
    }
  }
  const res = await getCoursePageList(params)
  if (res.data && res.data.data) {
    courses.value = res.data.data.list || []
    pagination.total = res.data.data.total || 0
  } else {
    courses.value = []
    pagination.total = 0
  }
  loading.value = false
}

// 监听分页变化
watch([() => pagination.current, () => pagination.pageSize], fetchCourses)

function handleSearch() {
  pagination.current = 1
  fetchCourses()
}
function resetFilters() {
  searchKeyword.value = ''
  selectedCategoryId.value = null
  pagination.current = 1
  fetchCourses()
}

// 课程弹窗
function openCourseModal(course: any, type: 'add' | 'edit') {
  courseModalType.value = type
  if (type === 'add') {
    Object.assign(courseForm, { id: null, title: '', categoryId: null, coverUrl: '', description: '' })
    fileList.value = []
    courseEditId.value = null
  } else {
    Object.assign(courseForm, course)
    fileList.value = course.coverUrl
      ? [{ url: PIC_BASE_URL + course.coverUrl }]
      : []
    courseEditId.value = course.id
  }
  showCourseModal.value = true
}
async function handleCourseModalOk() {
  if (!courseForm.title || !courseForm.categoryId) return
  if (courseModalType.value === 'add') {
    await addCourseBase({
      title: courseForm.title,
      categoryId: courseForm.categoryId,
      coverUrl: courseForm.coverUrl,
      description: courseForm.description
    })
  } else if (courseModalType.value === 'edit' && courseEditId.value) {
    await updateCourseBase({
      id: courseEditId.value,
      title: courseForm.title,
      categoryId: courseForm.categoryId,
      coverUrl: courseForm.coverUrl,
      description: courseForm.description
    })
  }
  showCourseModal.value = false
  fetchCourses()
}
async function deleteCourse(id: number) {
  await deleteCourseBase({ id })
  fetchCourses()
}
// 上传图片
async function beforeUpload(file: File) {
  const res: any = await uploadPic({}, file)
  if (res && res.data && res.data.data && res.data.data.filePath) {
    courseForm.coverUrl = res.data.data.filePath // 只存 filePath
    fileList.value = [{ url: PIC_BASE_URL + res.data.data.filePath, originFileObj: file }]
  }
  return false
}

// 计算文件md5
async function getFileMd5(file: File | Blob): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = function (e) {
      const binary = e.target?.result as ArrayBuffer
      const md5 = SparkMD5.ArrayBuffer.hash(binary)
      resolve(md5)
    }
    reader.onerror = reject
    reader.readAsArrayBuffer(file)
  })
}
// 下载图片为Blob
async function urlToBlob(url: string): Promise<Blob> {
  const response = await fetch(url)
  return await response.blob()
}
// 删除封面
async function removeCover() {
  if (courseForm.coverUrl) {
    let file: File | Blob | null = null
    if (fileList.value.length && fileList.value[0].originFileObj) {
      file = fileList.value[0].originFileObj
    } else {
      file = await urlToBlob(PIC_BASE_URL + courseForm.coverUrl)
    }
    if (file) {
      const fileMd5 = await getFileMd5(file)
      try {
        await deleteFile({ fileMd5 })
      } catch (e) {
        console.error('删除文件失败', e)
      }
    }
  }
  courseForm.coverUrl = ''
  fileList.value = []
}

// 课程大纲（接口实现）
const showOutlineModal = ref(false)
const outlineTree = ref<any[]>([])
const currentCourseId = ref<number | null>(null)
// 获取大纲树后补充level字段
function addLevelToTree(tree: any[], level = 1): any[] {
  return tree.map(node => ({
    ...node,
    level,
    children: node.children ? addLevelToTree(node.children, level + 1) : []
  }))
}
async function manageOutline(course: any) {
  currentCourseId.value = course.id
  // 获取大纲树
  const res = await getCourseOutlines({ courseId: course.id })
  if (res.data && res.data.data) {
    outlineTree.value = addLevelToTree(res.data.data)
  } else {
    outlineTree.value = []
  }
  showOutlineModal.value = true
}
// 大纲节点增删改
const showEditOutlineModal = ref(false)
const outlineModalType = ref<'add' | 'edit'>('add')
const outlineModalName = ref('')
const outlineEditId = ref<number | null>(null)
const outlineParentId = ref<number | null>(null)
function openOutlineModal(id: number | null, type: 'add' | 'edit') {
  outlineModalType.value = type
  if (type === 'add') {
    outlineModalName.value = ''
    outlineParentId.value = id
    outlineEditId.value = null
  } else {
    const node = findOutlineNode(outlineTree.value, id as number)
    outlineModalName.value = node?.title || ''
    outlineEditId.value = id
    outlineParentId.value = null
  }
  showEditOutlineModal.value = true
}
async function handleOutlineModalOk() {
  if (!outlineModalName.value) return
  if (outlineModalType.value === 'add') {
    // 计算同级节点的最大排序值 sortOrder
    let siblings: any[] = []
    if (outlineParentId.value) {
      // 找到父节点
      const parent = findOutlineNode(outlineTree.value, outlineParentId.value)
      siblings = parent && parent.children ? parent.children : []
    } else {
      // 新增顶级节点
      siblings = outlineTree.value
    }
    const maxSortOrder = siblings.length > 0
      ? Math.max(...siblings.map(n => n.sortOrder ?? 0))
      : 0
    await saveCourseOutlines({
      courseId: currentCourseId.value ?? undefined,
      parentId: outlineParentId.value ?? undefined,
      title: outlineModalName.value,
      sortOrder: maxSortOrder + 1
    })
  } else if (outlineModalType.value === 'edit' && outlineEditId.value) {
    await updateCourseOutlines({
      id: outlineEditId.value,
      title: outlineModalName.value
    })
  }
  showEditOutlineModal.value = false
  if (currentCourseId.value) await manageOutline({ id: currentCourseId.value })
}
async function deleteOutline(id: number) {
  await deleteCourseOutlines({ id })
  if (currentCourseId.value) await manageOutline({ id: currentCourseId.value })
}
function findOutlineNode(nodes: any[], id: number): any {
  for (const node of nodes) {
    if (node.id === id) return node
    if (node.children) {
      const found = findOutlineNode(node.children, id)
      if (found) return found
    }
  }
  return null
}
// 绑定视频（如有视频字段，调用 updateCourseOutlines）
const showBindVideoModal = ref(false)
const bindVideoNodeId = ref<number | null>(null)
const videoFileList = ref([])
function bindVideo(nodeId: number) {
  bindVideoNodeId.value = nodeId
  showBindVideoModal.value = true
}
async function handleBindVideo() {
  // 这里应上传视频并将视频id绑定到大纲节点
  // 假设上传视频后拿到 videoId
  const videoId = Date.now() // 这里请替换为实际上传逻辑
  await updateCourseOutlines({
    id: bindVideoNodeId.value ?? undefined,
    videoId
  })
  showBindVideoModal.value = false
  if (currentCourseId.value) await manageOutline({ id: currentCourseId.value })
}
function beforeVideoUpload(file: File) {
  // 上传逻辑
  return false
}

// 绑定视频弹窗相关逻辑
const videoSearchKeyword = ref('')
const videoList = ref<any[]>([])
const videoLoading = ref(false)
const videoPagination = reactive({
  current: 1,
  pageSize: 8,
  total: 0,
  showSizeChanger: true,
  showQuickJumper: true,
  showTotal: (total: number) => `共 ${total} 条视频`,
  pageSizeOptions: ['8', '16', '32']
})
const videoColumns = [
  { title: '视频名称', dataIndex: 'fileName', width: 200, align: 'center' },
  { title: '上传时间', dataIndex: 'createTime', width: 180, align: 'center' },
  { title: '操作', dataIndex: 'action', width: 100, align: 'center' }
]
async function fetchVideoList() {
  videoLoading.value = true
  const params = {
    videoPageListVo: {
      current: videoPagination.current,
      pageSize: videoPagination.pageSize,
      fileName: videoSearchKeyword.value
    }
  }
  const res = await getMediaFileList(params)
  if (res.data && res.data.data) {
    videoList.value = res.data.data.list || []
    videoPagination.total = res.data.data.total || 0
  } else {
    videoList.value = []
    videoPagination.total = 0
  }
  videoLoading.value = false
}
function handleVideoTableChange(pagination: any) {
  videoPagination.current = pagination.current
  videoPagination.pageSize = pagination.pageSize
  fetchVideoList()
}
async function selectVideo(video: any) {
  await updateCourseOutlines({
    id: bindVideoNodeId.value ?? undefined,
    videoId: video.id
  })
  showBindVideoModal.value = false
  message.success('绑定视频成功')
  if (currentCourseId.value) await manageOutline({ id: currentCourseId.value })
}

// 表格列
const columns = [
  { title: '封面', dataIndex: 'coverUrl', width: 80, align: 'center' },
  { title: '课程名称', dataIndex: 'title', width: 200, align: 'center' },
  { title: '创建时间', dataIndex: 'createTime', width: 150, align: 'center' },
  { title: '操作', dataIndex: 'action', width: 200, fixed: 'right',align: 'center' }
]

const showPreviewModal = ref(false)
const previewVideoUrl = ref('')
async function previewVideo(videoId: number) {
  // 通过 videoId 查询视频详情
  const res = await getMediaFileById({ id: videoId })
  if (res.data && res.data.data && res.data.data.filePath) {
    previewVideoUrl.value = VIDEO_BASE_URL + res.data.data.filePath
    showPreviewModal.value = true
  } else {
    previewVideoUrl.value = ''
  }
}
</script>

<style scoped>
.course-management {
  padding: 32px 0 0 0;
  background: #f7f8fa;
  min-height: 100vh;
}
.page-header {
  display: flex;
  align-items: center;
  margin-bottom: 24px;
  padding: 0 0 16px 0;
  background: none;
  box-shadow: none;
}
.page-header h1 {
  margin: 0;
  color: #222;
  font-size: 24px;
  font-weight: 700;
  flex: 1;
}
.page-header .ant-btn-primary {
  margin-left: 16px;
  height: 40px;
  font-size: 16px;
}
.search-section {
  background: #fff;
  padding: 20px 24px 12px 24px;
  border-radius: 12px;
  margin-bottom: 20px;
  box-shadow: 0 1px 4px rgba(0,0,0,0.03);
  display: flex;
  align-items: center;
  gap: 16px;
}
.search-section .ant-input-search {
  width: 320px;
}
.course-table {
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
  padding: 16px 0 0 0;
}
.course-cover {
  width: 60px;
  height: 45px;
  object-fit: cover;
  border-radius: 8px;
  border: 1.5px solid #e6e6e6;
  transition: transform 0.2s, box-shadow 0.2s;
  box-shadow: 0 1px 4px rgba(0,0,0,0.06);
}
.course-cover:hover {
  transform: scale(1.12);
  box-shadow: 0 4px 16px rgba(24,144,255,0.18);
  border-color: #1890ff;
}
.category-tree-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 15px;
  font-weight: 500;
  color: #333;
  padding: 2px 0;
  border-radius: 6px;
  transition: background 0.2s;
}
.category-tree-title:hover {
  background: #f0f5ff;
}
.category-tree-title .actions {
  opacity: 0;
  transition: opacity 0.2s;
}
.category-tree-title:hover .actions {
  opacity: 1;
}
.outline-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 15px;
  font-weight: 500;
  color: #333;
  padding: 2px 0;
}
.outline-title .actions {
  margin-left: 16px;
  display: flex;
  gap: 2px;
}
.outline-title .actions .ant-btn-link {
  padding: 0 4px;
  font-size: 13px;
  color: #888;
  border-radius: 4px;
  transition: background 0.15s, color 0.15s;
}
.outline-title .actions .ant-btn-link:hover {
  background: #e6f7ff;
  color: #1890ff;
}
.ant-card {
  border-radius: 14px !important;
  box-shadow: none;
  background: #fff;
}
.ant-tree {
  background: transparent;
}
.ant-modal-content {
  border-radius: 14px;
  padding: 32px 40px;
}
.ant-modal-header {
  border-radius: 14px 14px 0 0;
}
.ant-form-item {
  margin-bottom: 24px;
}
.ant-btn-primary {
  border-radius: 8px;
  height: 40px;
}
.ant-btn-link {
  border-radius: 4px;
}
.ant-upload-select-picture-card {
  width: 120px;
  height: 90px;
  border-radius: 10px;
}
.ant-upload-select-picture-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 10px;
}
.category-tree-title .actions {
  margin-left: 16px;
  display: flex;
  gap: 2px;
}
.cover-remove-btn {
  position: absolute;
  top: 4px;
  right: 4px;
  font-size: 20px;
  color: #ff4d4f;
  cursor: pointer;
  background: rgba(255,255,255,0.85);
  border-radius: 50%;
  box-shadow: 0 2px 8px rgba(0,0,0,0.10);
  transition: background 0.2s, color 0.2s, box-shadow 0.2s;
  z-index: 2;
  padding: 2px;
  line-height: 1;
}
.cover-remove-btn:hover {
  background: #fff;
  color: #d9363e;
  box-shadow: 0 4px 16px rgba(255,77,79,0.18);
}
.bind-video-btn {
  color: #1890ff;
  border: 1px solid #91d5ff;
  background: #fff;
  border-radius: 4px;
  font-weight: 500;
  padding: 0 10px;
  height: 24px;
  line-height: 22px;
  display: inline-flex;
  align-items: center;
  transition: border 0.2s, color 0.2s, background 0.2s;
}
.bind-video-btn:hover {
  color: #096dd9;
  border-color: #40a9ff;
  background: #e6f7ff;
}
.bind-video-btn-success {
  color: #52c41a !important;
  border: 1px solid #b7eb8f !important;
  background: #fff !important;
  font-weight: 500;
  padding: 0 10px;
  height: 24px;
  line-height: 22px;
  display: inline-flex;
  align-items: center;
  transition: border 0.2s, color 0.2s, background 0.2s;
}
.bind-video-btn-success:hover {
  color: #389e0d !important;
  border-color: #95de64 !important;
  background: #f6ffed !important;
}
</style>
